package controller

import (
	"encoding/json"
	"fmt"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	alipay "github.com/smartwalle/alipay/v3"
	"github.com/streadway/amqp"

	"myproject/utils"
)

//总路由分发
func News(newsGrp *gin.RouterGroup) {
	newsGrp.Use().POST("/addnews", addNews)
	newsGrp.Use().GET("/getnews", getNews)
	//获取支付宝地址
	newsGrp.Use().GET("/getpayurl", getpayurl)
	//回调接口
	newsGrp.Use().GET("/callback", callback)

	//SocketLink
	// newsGrp.Use().GET("/SocketLink", SocketLink)
	// //getmes
	// newsGrp.Use().GET("/sendSms", sendSms)
	//建立连接
	newsGrp.Use().GET("/socketConn", socketConn)
	//发送消息
	newsGrp.Use().GET("/socketSend", socketSend)

	//testmq
	newsGrp.Use().GET("/send", testmq)
	//worker
	newsGrp.Use().GET("/worker", worker)
	//kefuConn
	newsGrp.Use().GET("/kefuConn", kefuConn)
	//userlogin
	newsGrp.Use().GET("/userlogin", userlogin)

}

var (
	upgrader = websocket.Upgrader{
		ReadBufferSize:   1024,
		WriteBufferSize:  1024,
		CheckOrigin:      func(r *http.Request) bool { return true },
		HandshakeTimeout: time.Duration(time.Second * 5),
	}
)

//定义用户结构体
type Userinfo struct {
	Id   string
	Name string
}

//在线用户列表
var Userlist []*Userinfo

//建立websoket链接
func kefuConn(c *gin.Context) {
	id := c.Query("id")
	//建立连接
	conn, _ := upgrader.Upgrade(c.Writer, c.Request, nil)
	//保存连接
	utils.Scoketmap[id] = conn
	//删除user1
	delete(utils.Scoketmap, "1")
	//加入用户在线列表中
	if id != "kefu" {
		userinfo := &Userinfo{
			Id:   id,
			Name: "用户" + id,
		}
		Userlist = append(Userlist, userinfo)
	}

	//接收消息转发
	for {
		msgType, msgData, _ := conn.ReadMessage()

		if id == "kefu" {
			//读取消息，转成Json
			var mesMap = make(map[string]string)
			json.Unmarshal([]byte(string(msgData)), &mesMap)

			userid := mesMap["userid"]
			//判断用户是否已经连接
			userconn, ok := utils.Scoketmap[userid]
			if ok {
				userconn.WriteMessage(msgType, []byte(mesMap["mes"]))
			} else {
				fmt.Println("&&&&")
				//如果下线存在mq
				myqueue := "socketmes" + userid
				//ListAdd
				// utils.RedisPool.ListGetAll(myqueue)
				utils.RedisPool.ListAdd(myqueue, mesMap["mes"])

			}

		} else {
			//用户给客服发信息
			var returnData = make(map[string]interface{})
			returnData["message"] = string(msgData)
			returnData["userlist"] = Userlist
			ulist, _ := json.Marshal(returnData)
			utils.Scoketmap["kefu"].WriteMessage(msgType, ulist)
		}
	}
}

// type WebUser struct {
// 	Id   string
// 	Name string
// }

// var OnlineUser []*WebUser

// //建立websoket链接
// func kefuConn(c *gin.Context) {
// 	id := c.Query("id")
// 	//建立连接
// 	conn, _ := upgrader.Upgrade(c.Writer, c.Request, nil)
// 	//保存连接
// 	utils.Scoketmap[id] = conn
// 	delete(utils.Scoketmap, "1")

// 	//更新在线用户
// 	suser := &WebUser{
// 		Id:   id,
// 		Name: "用户" + id,
// 	}
// 	if id != "kefu" {
// 		OnlineUser = append(OnlineUser, suser)
// 	}

// 	//接收消息转发
// 	for {
// 		msgType, msgData, _ := conn.ReadMessage()

// 		if id == "kefu" {
// 			class_detail_map := make(map[string]string)
// 			json.Unmarshal([]byte(string(msgData)), &class_detail_map)

// 			mes := "客服说:" + class_detail_map["mes"]
// 			userid := class_detail_map["userid"]
// 			userconn, ok := utils.Scoketmap[userid]
// 			if ok {
// 				userconn.WriteMessage(msgType, []byte(mes))
// 			} else {
// 				//存mq
// 				// 初始化mq
// 				mq := utils.NewRabbitMQ()
// 				defer mq.ReleaseRes() // 完成任务释放资源
// 				myqueue := "queue" + userid
// 				myexchange := "socketmes"
// 				_, err := mq.Channel.QueueDeclare( // 返回的队列对象内部记录了队列的一些信息，这里没什么用
// 					myqueue, // 队列名
// 					true,    // 是否持久化
// 					false,   // 是否自动删除(前提是至少有一个消费者连接到这个队列，之后所有与这个队列连接的消费者都断开时，才会自动删除。注意：生产者客户端创建这个队列，或者没有消费者客户端与这个队列连接时，都不会自动删除这个队列)
// 					false,   // 是否为排他队列（排他的队列仅对“首次”声明的conn可见[一个conn中的其他channel也能访问该队列]，conn结束后队列删除）
// 					false,   // 是否阻塞
// 					nil,     //额外属性（我还不会用）
// 				)
// 				if err != nil {
// 					fmt.Println("声明队列失败", err)
// 					return
// 				}

// 				// 2.声明交换器
// 				err = mq.Channel.ExchangeDeclare(
// 					myexchange, //交换器名
// 					"topic",    //exchange type：一般用fanout、direct、topic
// 					true,       // 是否持久化
// 					false,      //是否自动删除（自动删除的前提是至少有一个队列或者交换器与这和交换器绑定，之后所有与这个交换器绑定的队列或者交换器都与此解绑）
// 					false,      //设置是否内置的。true表示是内置的交换器，客户端程序无法直接发送消息到这个交换器中，只能通过交换器路由到交换器这种方式
// 					false,      // 是否阻塞
// 					nil,        // 额外属性
// 				)
// 				if err != nil {
// 					fmt.Println("声明交换器失败", err)
// 					return
// 				}

// 				// 3.建立Binding(可随心所欲建立多个绑定关系)
// 				err = mq.Channel.QueueBind(
// 					myqueue,    // 绑定的队列名称
// 					"index",    // bindkey 用于消息路由分发的key
// 					myexchange, // 绑定的exchange名
// 					false,      // 是否阻塞
// 					nil,        // 额外属性
// 				)

// 				if err != nil {
// 					fmt.Println("绑定队列和交换器失败", err)
// 					return
// 				}

// 				// 4.发送消息
// 				mq.Channel.Publish(
// 					myexchange, // 交换器名
// 					"index",    // routing key
// 					false,      // 是否返回消息(匹配队列)，如果为true, 会根据binding规则匹配queue，如未匹配queue，则把发送的消息返回给发送者
// 					false,      // 是否返回消息(匹配消费者)，如果为true, 消息发送到queue后发现没有绑定消费者，则把发送的消息返回给发送者
// 					amqp.Publishing{ // 发送的消息，固定有消息体和一些额外的消息头，包中提供了封装对象
// 						ContentType: "text/plain", // 消息内容的类型
// 						Body:        []byte(mes),  // 消息内容
// 					},
// 				)
// 			}

// 		} else {
// 			mes := suser.Name + "说：" + string(msgData)
// 			var mesmap = make(map[string]interface{})
// 			mesmap["mes"] = mes
// 			mesmap["userlist"] = OnlineUser
// 			returnmes, _ := json.Marshal(mesmap)
// 			utils.Scoketmap["kefu"].WriteMessage(msgType, returnmes)
// 		}
// 	}
// }

func userlogin(c *gin.Context) {
	userid := c.Query("id")
	myqueue := "socketmes" + userid
	//ListAdd
	res := utils.RedisPool.ListGetAll(myqueue)
	fmt.Println(res)

}

//获取支付宝地址
func getpayurl(c *gin.Context) {
	utils.Init()
	var p = alipay.TradePagePay{}
	p.NotifyURL = "http://localhost:8000/news/callback"
	p.ReturnURL = "http://localhost:8000/news/callback"
	p.Subject = "要充值"
	p.OutTradeNo = "1313423523"
	p.TotalAmount = "10.00"
	p.ProductCode = "FAST_INSTANT_TRADE_PAY"

	url, err := utils.Client.TradePagePay(p)
	if err != nil {
		c.JSON(200, gin.H{
			"code": 20010,
			"mes":  "获取",
		})
		return
	}
	fmt.Println(url)

	c.JSON(200, gin.H{
		"code": 200,
		"url":  url,
	})
}

//支付宝回调接口
func callback(c *gin.Context) {
	//难签
	order, err := utils.Client.GetTradeNotification(c.Request)
	alipay.AckNotification(c.Writer) // 确认收到通知消息
	fmt.Println(err, order)
	if order == nil {
		fmt.Println("验证失败")
	} else {
		fmt.Println(order)
	}

}

// func pay(c *gin.Context) {
// 	var p = alipay.TradePagePay{}
// 	p.NotifyURL = "http://localhost:8000/news/callback"
// 	p.ReturnURL = "http://localhost:8000/news/callback"
// 	p.Subject = "修正了中文的 Bug"
// 	p.OutTradeNo = "111t1111rade_no_22201706230111212"
// 	p.TotalAmount = "10.00"
// 	p.ProductCode = "FAST_INSTANT_TRADE_PAY"

// 	url, err := utils.Client.TradePagePay(p)
// 	if err != nil {
// 		fmt.Println(nil)
// 	}
// 	fmt.Println(url)
// }

// func callBack(c *gin.Context) {
// 	// fmt.Println(c.Request)

// 	noti, err := utils.Client.GetTradeNotification(c.Request)
// 	if err != nil {
// 		fmt.Println("****")
// 		// c.Status(http.StatusInternalServerError)
// 		fmt.Println(err)
// 		return
// 	}
// 	fmt.Printf("订单号:%s;状态:%s\n", noti.OutTradeNo, noti.TradeStatus)
// 	c.String(http.StatusOK, "success")

// 	alipay.AckNotification(c.Writer) // 确认收到通知消息

// }

//添加新闻接口
func addNews(c *gin.Context) {
	var userid uint = 178
	token, _ := utils.ReleaseToken(userid)
	// fmt.Println(token)

	_, mes, _ := utils.ParseToken(token)
	fmt.Println("###")
	fmt.Println(mes.UserId)
	// conn, err := redis.Dial("tcp", )
	// _, err = conn.Do("Set", "name", "tomjerry 狗狗")
	// if err != nil {
	// 	fmt.Println("set err = ", err)
	// 	return
	// }
	// conn := utils.NewClient("127.0.0.1:6379", 1)
	// // 3.通过go向redis读取数据 string [key - val]
	// conn.Do("Set", "name", "tomjerry 狗狗")
	// r, err := redis.String(conn.Do("Get", "name"))
	// if err != nil {
	// 	fmt.Println("set err = ", err)
	// 	return
	// }
	// fmt.Println(r)

	// var user model.User
	// model.DB.First(&user)

	// token, _ := utils.ReleaseToken(user)
	// fmt.Println(token)
	// _, mes1, _ := utils.ParseToken(token)

	// fmt.Println(mes1.UserId)

	// news1 := &model.News{
	// 	Title:   news.Title,
	// 	Content: news.Content,
	// 	Userid:  news.Userid,
	// }
	// db := model.GetDb()
	// db.Create(news1)
	// fmt.Println(news1.ID)
	//分配审核人 1,2,3
	// idlist :=[]int{}
	// //查询审核人表，user表中type为2
	// idlist = append(idlist, 1)
	// idlist = append(idlist, 2)
	// idlist = append(idlist, 3)
	// //tcount = len(idlist)
	// //用新加的新闻的id id%tcount  0 idlist[0]

	// if res.Error != nil { //判断是否插入数据出错
	// 	// fmt.Println(res.Error)
	// 	c.JSON(200, gin.H{
	// 		"code": "10011",
	// 		"res":  "fail",
	// 	})
	// } else {
	// 	c.JSON(200, gin.H{
	// 		"code": "10010",
	// 		"res":  "ok",
	// 	})
	// }

}

//获取新闻接口
func getNews(c *gin.Context) {

	// var users []model.User
	// db := model.DB
	// db.Table("users").Find(&users)
	// for _, vv := range users {
	// 	fmt.Println(vv)
	// }

	// ulist, _ := json.Marshal(users)
	// r := utils.GetRedis()
	// r.Setex("mymmlist2", 100, ulist)
	// fmt.Println(r.Get("mymmlist2"))
	// news := r.Get("mymmlist2")
	// var usermes interface{}
	// json.Unmarshal([]byte(news), &usermes)
	// uu := usermes.([]interface{})
	// for _, v := range uu {
	// 	fmt.Println(v)
	// }
	// for _, v := range news {
	// 	fmt.Println(v)
	// }
	// r.ListPush("openlist", 1)
	// r.ListPush("openlist", 2)
	// r.ListPush("openlist", 3)
	// r.ListGetAll("openlist")

	// v := r.ListGetAll("openlist")
	// list1 := v.([]interface{})

	// for _, vv := range list1 {
	// 	fmt.Println(vv.([]uint8)[0])

	// }
	// len := r.ListGetLen("openlist")
	// fmt.Println(len)

	// c.JSON(200, gin.H{
	// 	"code":    "10010",
	// 	"neslist": uu,
	// })
}

// var scoketmap = make(map[string]*websocket.Conn)

// func SocketLink(c *gin.Context) {
// 	id := c.Query("id")

// 	conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
// 	scoketmap[id] = conn

// 	if err != nil {
// 		log.Println("cant upgrade connection:", err)
// 		return
// 	}
// 	var i = 0
// 	for {
// 		msgType, msgData, err := conn.ReadMessage()

// 		fmt.Println("*****", msgType)

// 		if err != nil {
// 			log.Println("cant read message:", err)
// 		}
// 		log.Printf("recv message: %s\n", msgData)
// 		i++
// 		conn.WriteMessage(msgType, []byte(msgData))
// 	}
// }

// func sendSms(c *gin.Context) {
// 	worker, _ := utils.NewWorker(1)

// 	id := worker.NextId()
// 	fmt.Println(id % 3)

// 	// i := "mess"
// 	// scoketmap["1"].WriteMessage(1, []byte(i))
// }

// var socketLink = make(map[string]*websocket.Conn)
// ip := c.RemoteIP()
func socketConn(c *gin.Context) {

	id := c.Query("id")
	//建立连接
	conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		c.JSON(200, gin.H{
			"code": 10010,
			"mes":  "连接错误",
		})
	}
	//存储在map中
	utils.Scoketmap[id] = conn

	for {
		msgType, msgData, err := conn.ReadMessage()
		// utils.Scoketmap["1"].WriteMessage(msgType, []byte(msgData))

		fmt.Println("*****", msgData)

		if err != nil {
			fmt.Println("cant read message:", err)
		}
		// log.Printf("recv message: %s\n", msgData)
		if id == "kefu" {
			utils.Scoketmap["1"].WriteMessage(msgType, []byte(msgData))
		} else {
			utils.Scoketmap["kefu"].WriteMessage(msgType, []byte(msgData))
		}

	}
}

func socketSend(c *gin.Context) {

	//从客户端获取消息
	mes := c.Query("mes")
	kefuid := c.Query("id")
	//从map中获取连接
	conn := utils.Scoketmap[kefuid]
	//发送消息给客户端
	conn.WriteMessage(1, []byte(mes))
}

//管理员发布信息
func testmq(c *gin.Context) {

	mes := c.Query("mes")
	types := c.Query("type")

	// mq := utils.NewRabbitMQ()
	// ch := mq.Channel
	mq, _ := amqp.Dial("amqp://guest:guest@localhost:5672")
	ch, _ := mq.Channel()
	err := ch.ExchangeDeclare("logs_topic", amqp.ExchangeTopic, true, false, false, false, nil)
	if err != nil {
		fmt.Println("333")
	}

	err = ch.Publish("logs_topic", utils.Typedict[types], false, false, amqp.Publishing{
		ContentType: "text/plain",
		Body:        []byte(mes),
	})

	if err != nil {
		fmt.Println("发送失败")
	}

}

func task(mes string) {
	//mes id title type
	//根据type查询数据库select * from table where type=3   1,2,3
	conn, ok := utils.Scoketmap["1"]
	if ok {
		// fmt.Println(mm)
		conn.WriteMessage(1, []byte(mes))
	} else {
		//存入队列,简单模式，队列名 message1
		fmt.Println("333")
	}
	fmt.Println("任务执行者", mes)
}

//建立mq连接绑定队列读取信息
func worker(c *gin.Context) {
	mq, _ := amqp.Dial("amqp://guest:guest@localhost:5672")
	ch, _ := mq.Channel()
	err := ch.ExchangeDeclare("logs_topic", amqp.ExchangeTopic, true, false, false, false, nil)
	if err != nil {
		fmt.Println("发送失败")
	}

	q, err := ch.QueueDeclare("", false, false, false, false, nil)
	if err != nil {
		fmt.Println("创建队列失败")
	}

	for _, key := range utils.Typedict {
		_ = ch.QueueBind(q.Name, key, "logs_topic", false, nil)
	}

	msgs, _ := ch.Consume(q.Name, "", true, false, false, false, nil)
	fmt.Println("****", msgs)
	for msg := range msgs {
		fmt.Println(msg.Body)
	}
	// go task(msgs.Body)
	// go func() {
	// 	for msg := range msgs {
	// 		log.Printf("Received a message: %s", msg.Body)
	// 	}
	// }()

}
